package com.middlegroup.pay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.middlegroup.common.constants.MethodConstants;
import com.middlegroup.common.enums.ChannelCode;
import com.middlegroup.common.enums.ConfigKeyEnums;
import com.middlegroup.common.enums.ServiceType;
import com.middlegroup.common.exception.BusinessException;
import com.middlegroup.common.exception.ErrorMsg;
import com.middlegroup.common.model.*;
import com.middlegroup.common.utils.AesUtils;
import com.middlegroup.common.utils.Base64Utils;
import com.middlegroup.common.utils.MaskUtils;
import com.middlegroup.common.utils.RSAUtils;
import com.middlegroup.pay.dto.RouterRequest;
import com.middlegroup.pay.dto.RouterResponse;
import com.middlegroup.pay.entity.*;
import com.middlegroup.pay.mapper.InBillsMapper;
import com.middlegroup.pay.mapper.ThirdProtocolBindCardMapper;
import com.middlegroup.pay.mapper.ThirdProtocolBindRecordMapper;
import com.middlegroup.pay.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.security.PrivateKey;
import java.text.ParseException;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

/**
 * @author pc
 * @date 2019/1/14
 */
@Service
@Slf4j
public class SubjectPayServiceImpl implements SubjectPayService {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private SubjectService subjectService;

    @Resource
    private MerchantService merchantService;

    @Resource
    private SystemCfgService systemCfgService;

    @Resource
    private OutNotifyMerchantLogService outNotifyMerchantLogService;

    @Resource
    private OutNotifyMerchantService outNotifyMerchantService;

    @Resource
    private ThirdBillsService thirdBillsService;

    @Resource
    private ThirdProtocolBindCardMapper thirdProtocolBindCardMapper;

    @Resource
    private ThirdProtocolBindRecordMapper thirdProtocolBindRecordMapper;

    @Resource
    private MerchantSubjectChannelRouterService merchantSubjectChannelRouterService;

    @Value("${userinfo.encryptor.aeskey}")
    private String userInfoEncryptKey;

    @Resource
    private CardBinService cardBinService;

    @Resource
    private InBillsMapper inBillsMapper;

    @Resource
    private TransBillsService transBillsService;


    @Override
    public TransResult df(TransRequest request) {
        TransResult transResult = post(MethodConstants.DF, request);
        return transResult;
    }

    @Override
    public TransResult deduct(TransRequest request) {
        TransResult transResult = post(MethodConstants.DEDUCT, request);
        return transResult;
    }

    @Override
    public TransResult protocolPay(TransRequest request) {
        //中台订单号
        String billNo = UUID.randomUUID().toString().replaceAll("-", "");
        if (null != request.getStep() && request.getStep().intValue() == 1) {
            request.setBillNo(billNo);
        }
        TransResult transResult = new TransResult();
        transResult.setMsg("处理中");
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setBillNo(request.getBillNo());
        transResult.setTransStatus(0);
        if (StringUtils.isBlank(request.getBillNo())) {
            transResult.setTransStatus(2);
            transResult.setMsg("billNo为空!");
            return transResult;
        }
        //TODO 路由  先判断该主体下有无做过协议支付绑卡的通道，如果有则直接使用该渠道，否则按规则路由
        RouterResponse routerResponse = null;

        ThirdProtocolBindCard thirdProtocolBindCardFind = new ThirdProtocolBindCard();
        //加密之后的卡号查询
        String cardNo = AesUtils.encrypt(request.getCardNo(), userInfoEncryptKey);
        thirdProtocolBindCardFind.setCardNo(cardNo);
        thirdProtocolBindCardFind.setSubjectCode(request.getSubjectCode());
        ThirdProtocolBindCard thirdProtocolBindCard = thirdProtocolBindCardMapper.selectOne(thirdProtocolBindCardFind);
        if (null != thirdProtocolBindCard) {
            routerResponse = new RouterResponse();
            routerResponse.setSubjectCode(request.getSubjectCode());
            routerResponse.setChannelCode(thirdProtocolBindCard.getChannelCode());
        }

        if (null == routerResponse) {
            //规则路由
            CardBin cardBin = cardBinService.getBankInfoByCardNo(request.getCardNo());
            if (null == cardBin) {
                //银行不支持
                transResult.setTransStatus(2);
                transResult.setMsg(ErrorMsg.NONSUPPORT_BANK);
                return transResult;
            }

            RouterRequest routerRequest = new RouterRequest();
            routerRequest.setBankCode(cardBin.getBankCode());
            routerRequest.setMerchantCode(request.getMerchantCode());
            routerRequest.setServiceType(ServiceType.PROTOCOL_PAY.name());
            routerRequest.setSubjectCode(request.getSubjectCode());
            try {
                routerResponse = merchantSubjectChannelRouterService.router(routerRequest);
            } catch (BusinessException e) {
                log.error("渠道路由失败，未找到渠道!");
            } catch (ParseException e) {
                log.error("时间表达式转化出错，请检查!");
            }
            if (null == routerResponse) {
                log.error(ErrorMsg.NOT_CONFIG_ROUTER);
                transResult.setTransStatus(2);
                transResult.setMsg(ErrorMsg.NOT_CONFIG_ROUTER);
                return transResult;
            }
            ChannelCode channelCode = ChannelCode.valueOf(routerResponse.getChannelCode());
            request.setChannelCode(channelCode);
        }

        try {
            transResult = post(MethodConstants.PROTOCOL_PAY, request);
        } catch (Exception e) {
            log.error("调用subjectpay失败", e);
        }
        //插入交易流程订单表
        if (Integer.compare(1, request.getStep()) == 0) {
            TransBills transBills = new TransBills();
            transBills.setChannelCode(request.getChannelCode().name());
            transBills.setMerchantCode(request.getMerchantCode());
            transBills.setSubjectCode(request.getSubjectCode());
            transBills.setMerchantBillNo(request.getMerchantBillNo());
            transBills.setBillNo(request.getBillNo());
            transBills.setAmount(request.getAmount());
            transBills.setStatus(transResult.getTransStatus());
            transBills.setAmount(request.getAmount());
            transBills.setServiceType(ServiceType.PROTOCOL_PAY.name());
            transBillsService.insert(transBills);
        }
        //如果是确认扣款步骤则记录Inbills
        if (Integer.compare(2, request.getStep()) == 0 || Integer.compare(3, request.getStep()) == 0 || Integer.compare(4, request.getStep()) == 0) {
            InBills bills = new InBills();
            bills.setChannelCode(request.getChannelCode().name());
            bills.setMerchantCode(request.getMerchantCode());
            bills.setSubjectCode(request.getSubjectCode());
            bills.setMerchantBillNo(request.getMerchantBillNo());
            bills.setBillNo(request.getBillNo());
            bills.setAmount(request.getAmount());
            bills.setName(MaskUtils.maskName(request.getName()));
            bills.setIdCard(MaskUtils.maskIDCardNo(request.getIdCard()));
            bills.setCardNo(MaskUtils.maskBankCardNo(request.getCardNo()));
            bills.setPhone(MaskUtils.maskCellphone(request.getPhone()));
            bills.setNameEnc(AesUtils.encrypt(request.getName(), userInfoEncryptKey));
            bills.setIdCardEnc(AesUtils.encrypt(request.getIdCard(), userInfoEncryptKey));
            bills.setPhoneEnc(AesUtils.encrypt(request.getPhone(), userInfoEncryptKey));
            bills.setCardNoEnc(AesUtils.encrypt(request.getCardNo(), userInfoEncryptKey));
            bills.setServiceType(ServiceType.PROTOCOL_PAY);
            bills.setStatus(transResult.getTransStatus());
            inBillsMapper.insert(bills);
        }
        return transResult;
    }

    @Override
    public TransResult quickPay(TransRequest request) {
        //中台订单号
        String billNo = UUID.randomUUID().toString().replaceAll("-", "");
        request.setBillNo(billNo);
        TransResult transResult = new TransResult();
        transResult.setMsg("处理中");
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setBillNo(request.getBillNo());
        transResult.setTransStatus(0);
        RouterResponse routerResponse = null;

        if (null == routerResponse) {
            //规则路由
            CardBin cardBin = cardBinService.getBankInfoByCardNo(request.getCardNo());
            if (null == cardBin) {
                //银行不支持
                transResult.setTransStatus(2);
                transResult.setMsg(ErrorMsg.NONSUPPORT_BANK);
                return transResult;
            }

            RouterRequest routerRequest = new RouterRequest();
            routerRequest.setBankCode(cardBin.getBankCode());
            routerRequest.setMerchantCode(request.getMerchantCode());
            routerRequest.setServiceType(ServiceType.QUICK_PAY.name());
            routerRequest.setSubjectCode(request.getSubjectCode());
            try {
                routerResponse = merchantSubjectChannelRouterService.router(routerRequest);
            } catch (BusinessException e) {
                log.error("渠道路由失败，未找到渠道!");
            } catch (ParseException e) {
                log.error("时间表达式转化出错，请检查!");
            }
            if (null == routerResponse) {
                log.error(ErrorMsg.NOT_CONFIG_ROUTER);
                transResult.setTransStatus(2);
                transResult.setMsg(ErrorMsg.NOT_CONFIG_ROUTER);
                return transResult;
            }
            ChannelCode channelCode = ChannelCode.valueOf(routerResponse.getChannelCode());
            request.setChannelCode(channelCode);
        }

        try {
            transResult = post(MethodConstants.QUICK_PAY, request);
        } catch (Exception e) {
            log.error("快捷支付调用subjectpay失败", e);
        }
        //插入交易流程订单表
        if (Integer.compare(1, request.getStep()) == 0) {
            TransBills transBills = new TransBills();
            transBills.setChannelCode(request.getChannelCode().name());
            transBills.setMerchantCode(request.getMerchantCode());
            transBills.setSubjectCode(request.getSubjectCode());
            transBills.setMerchantBillNo(request.getMerchantBillNo());
            transBills.setBillNo(request.getBillNo());
            transBills.setAmount(request.getAmount());
            transBills.setStatus(transResult.getTransStatus());
            transBills.setServiceType(ServiceType.QUICK_PAY.name());
            transBills.setAmount(request.getAmount());
            transBillsService.insert(transBills);
        }
        //如果是确认扣款步骤则记录Inbills
        if (Integer.compare(2, request.getStep()) == 0 || Integer.compare(3, request.getStep()) == 0 || Integer.compare(4, request.getStep()) == 0) {
            InBills bills = new InBills();
            bills.setChannelCode(request.getChannelCode().name());
            bills.setMerchantCode(request.getMerchantCode());
            bills.setSubjectCode(request.getSubjectCode());
            bills.setMerchantBillNo(request.getMerchantBillNo());
            bills.setBillNo(request.getBillNo());
            bills.setAmount(request.getAmount());
            bills.setName(MaskUtils.maskName(request.getName()));
            bills.setIdCard(MaskUtils.maskIDCardNo(request.getIdCard()));
            bills.setCardNo(MaskUtils.maskBankCardNo(request.getCardNo()));
            bills.setPhone(MaskUtils.maskCellphone(request.getPhone()));
            bills.setNameEnc(AesUtils.encrypt(request.getName(), userInfoEncryptKey));
            bills.setIdCardEnc(AesUtils.encrypt(request.getIdCard(), userInfoEncryptKey));
            bills.setPhoneEnc(AesUtils.encrypt(request.getPhone(), userInfoEncryptKey));
            bills.setCardNoEnc(AesUtils.encrypt(request.getCardNo(), userInfoEncryptKey));
            bills.setServiceType(ServiceType.PROTOCOL_PAY);
            bills.setStatus(transResult.getTransStatus());
            inBillsMapper.insert(bills);
        }
        return transResult;
    }

    @Override
    @Async("asyncServiceExecutor")
    public void notifyMerchant(String merchantCode, String method, NotifyRequest request) {

        //TODO 判断是否已经通知了最大次数
        EntityWrapper<OutNotifyMerchant> entityWrapper = new EntityWrapper<>();
        entityWrapper.where("bill_no={0}", request.getBillNo());
        OutNotifyMerchant outNotifyMerchant = outNotifyMerchantService.selectOne(entityWrapper);
        if (null == outNotifyMerchant) {
            //若无查到则初始化插入一条数据
            outNotifyMerchant = new OutNotifyMerchant();
            outNotifyMerchant.setBillNo(request.getBillNo());
            outNotifyMerchant.setStatus(0);
            outNotifyMerchant.setBeginTime(System.currentTimeMillis());
            outNotifyMerchant.setMerchantCode(merchantCode);
            outNotifyMerchant.setMerchantBillNo(request.getMerchantBillNo());
            outNotifyMerchant.setNotifyTimes(0);
            outNotifyMerchantService.insert(outNotifyMerchant);
        }
        if (outNotifyMerchant.getNotifyTimes().intValue() >= 5) {
            //如果通知次数超过阀值了，则直接返回
            return;
        }


        Merchant merchant = merchantService.getMerchantByCode(merchantCode);
        if (null == merchant) {
            //商户不存在
            log.error("未找到对应商户!请检查配置!");
            return;
        }

        String url = merchant.getServiceUrl();
        if (StringUtils.isBlank(url)) {
            log.error("商户未配置回调地址，请联系管理员!");
            return;
        }

        //商户公钥加密aes 的key
        String merchantPubKeyStr = merchant.getRsaPubKey();
        //平台私钥签名
        String privateKeyStr = systemCfgService.getConfigString(ConfigKeyEnums.PAY_PLATFORM_RSA_PRI_KEY.getCategory(), ConfigKeyEnums.PAY_PLATFORM_RSA_PRI_KEY.getName());
        if (StringUtils.isBlank(privateKeyStr)) {
            log.error("支付中台rsa私钥缺失!");
            return;
        }

        String aesKey = RandomStringUtils.randomAlphanumeric(16);
        String reqData = null;
        String oldAesKey = aesKey;

        //使用明文aesKey加密业务数据
        try {
            reqData = AesUtils.encrypt(JSONObject.toJSONString(request), aesKey);
        } catch (Exception e) {
            log.error("Aes加密业务数据失败", e);
            return;
        }
        //使用商户公钥加密aesKey
        try {
            aesKey = new String(Base64Utils.encode(RSAUtils.encryptByPublicKey(aesKey.getBytes("UTF-8"), merchantPubKeyStr)));
        } catch (Exception e) {
            log.error("RSA加密AES密钥失败", e);
            return;
        }

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        postParameters.add("aesKey", aesKey);
        postParameters.add("merchantCode", merchantCode);
        postParameters.add("method", method);
        postParameters.add("reqData", reqData);

        Map<String, String> params = new TreeMap<String, String>();
        params.put("aesKey", aesKey);
        params.put("merchantCode", merchantCode);
        params.put("method", method);
        params.put("reqData", reqData);
        String jsoStr = JSONObject.toJSONString(params);

        //中台私钥签名
        PrivateKey privateKey = RSAUtils.readPrivateKey(privateKeyStr);
        String sign = null;
        try {
            sign = RSAUtils.sign("SHA1WithRSA", jsoStr.getBytes("UTF-8"), privateKey);
        } catch (Exception e) {
            log.error("中台私钥签名失败", e);
            return;
        }
        postParameters.add("sign", sign);
        ResponseEntity responseDto = null;
        //商户回调日志记录
        OutNotifyMerchantLog outNotifyMerchantLog = new OutNotifyMerchantLog();
        outNotifyMerchantLog.setStatus(0);
        outNotifyMerchantLog.setMerchantBillNo(request.getMerchantBillNo());
        outNotifyMerchantLog.setBillNo(request.getBillNo());
        outNotifyMerchantLog.setMerchantCode(merchantCode);
        outNotifyMerchantLog.setRequestText(JSONObject.toJSONString(postParameters));
        outNotifyMerchantLog.setBeginTime(System.currentTimeMillis());

        try {
            responseDto = restTemplate.postForObject(url, postParameters, ResponseEntity.class);
            //商户响应200
            outNotifyMerchantLog.setStatus(1);
        } catch (Exception e) {
            log.error("回调通知商户异常", e);
            //异常
            outNotifyMerchantLog.setStatus(3);
        }
        outNotifyMerchantLog.setEndTime(System.currentTimeMillis());

        String retData = null;
        try {
            retData = AesUtils.decrypt((String) responseDto.getData(), oldAesKey);
        } catch (Exception e) {
            log.error("解密商户响应数据失败!", e);
        }
        outNotifyMerchantLog.setResponseText(retData);
        boolean rt = outNotifyMerchantLogService.insert(outNotifyMerchantLog);
        if (rt) {
            //更新notify_merchant
            outNotifyMerchantService.updateTimes(request.getBillNo());
        }
    }

    @Override
    public TransResult bindCard(BindCardDto bindCardDto) {
        //中台订单号
        String billNo = UUID.randomUUID().toString().replaceAll("-", "");
        bindCardDto.setBillNo(billNo);
        TransResult transResult = new TransResult();
        transResult.setMsg("处理中");
        transResult.setMerchantBillNo(bindCardDto.getMerchantBillNo());
        transResult.setBillNo(bindCardDto.getBillNo());
        transResult.setTransStatus(0);
        //TODO 路由  先判断该主体下有无做过协议支付绑卡的通道，如果有则直接使用该渠道，否则按规则路由
        RouterResponse routerResponse = null;

        ThirdProtocolBindCard thirdProtocolBindCardFind = new ThirdProtocolBindCard();
        //加密之后的卡号查询
        String cardNo = AesUtils.encrypt(bindCardDto.getCardNo(), userInfoEncryptKey);
        thirdProtocolBindCardFind.setCardNo(cardNo);
        thirdProtocolBindCardFind.setSubjectCode(bindCardDto.getSubjectCode());
        ThirdProtocolBindCard thirdProtocolBindCard = thirdProtocolBindCardMapper.selectOne(thirdProtocolBindCardFind);
        if (null != thirdProtocolBindCard) {
            routerResponse = new RouterResponse();
            routerResponse.setSubjectCode(bindCardDto.getSubjectCode());
            routerResponse.setChannelCode(thirdProtocolBindCard.getChannelCode());
        }

        if (null == routerResponse) {
            //规则路由
            CardBin cardBin = cardBinService.getBankInfoByCardNo(bindCardDto.getCardNo());
            if (null == cardBin) {
                //银行不支持
                transResult.setTransStatus(2);
                transResult.setMsg(ErrorMsg.NONSUPPORT_BANK);
                return transResult;
            }

            RouterRequest routerRequest = new RouterRequest();
            routerRequest.setBankCode(cardBin.getBankCode());
            routerRequest.setMerchantCode(bindCardDto.getMerchantCode());
            routerRequest.setServiceType(ServiceType.PROTOCOL_PAY.name());
            routerRequest.setSubjectCode(bindCardDto.getSubjectCode());
            try {
                routerResponse = merchantSubjectChannelRouterService.router(routerRequest);
            } catch (BusinessException e) {
                log.error("渠道路由失败，未找到渠道!");
            } catch (ParseException e) {
                log.error("时间表达式转化出错，请检查!");
            }
            if (null == routerResponse) {
                log.error(ErrorMsg.NOT_CONFIG_ROUTER);
                transResult.setTransStatus(2);
                transResult.setMsg(ErrorMsg.NOT_CONFIG_ROUTER);
                return transResult;
            }
            ChannelCode channelCode = ChannelCode.valueOf(routerResponse.getChannelCode());
            bindCardDto.setChannelCode(channelCode);
        }

        //找到合适渠道
        //插入绑卡流程记录表
        ThirdProtocolBindRecord thirdProtocolBindRecord = new ThirdProtocolBindRecord();
        thirdProtocolBindRecord.setSubjectCode(bindCardDto.getSubjectCode());
        thirdProtocolBindRecord.setMerchantBillNo(bindCardDto.getMerchantBillNo());
        thirdProtocolBindRecord.setBillNo(bindCardDto.getBillNo());
        thirdProtocolBindRecord.setStatus(0);
        //掩码敏感信息
        thirdProtocolBindRecord.setName(MaskUtils.maskName(bindCardDto.getName()));
        thirdProtocolBindRecord.setIdCard(MaskUtils.maskIDCardNo(bindCardDto.getIdCard()));
        thirdProtocolBindRecord.setPhone(MaskUtils.maskCellphone(bindCardDto.getPhone()));
        thirdProtocolBindRecord.setCardNo(MaskUtils.maskBankCardNo(bindCardDto.getCardNo()));
        thirdProtocolBindRecord.setChannelCode(routerResponse.getChannelCode());
        int rt = thirdProtocolBindRecordMapper.insert(thirdProtocolBindRecord);
        if (rt > 0) {
            //记录成功则发往subjectpay服务
            TransRequest transRequest = new TransRequest();
            transRequest.setMerchantCode(bindCardDto.getMerchantCode());
            //此处一定要设置
            transRequest.setSubjectCode(bindCardDto.getSubjectCode());
            transRequest.setMerchantBillNo(bindCardDto.getMerchantBillNo());
            transRequest.setBillNo(bindCardDto.getBillNo());
            transRequest.setPhone(bindCardDto.getPhone());
            transRequest.setCardNo(bindCardDto.getCardNo());
            transRequest.setIdCard(bindCardDto.getIdCard());
            transRequest.setName(bindCardDto.getName());
            ChannelCode channelCode = ChannelCode.valueOf(routerResponse.getChannelCode());
            transRequest.setChannelCode(channelCode);
            transRequest.setSmsCode(bindCardDto.getSmsCode());

            transResult = post(MethodConstants.BIND_CARD, transRequest);
            if (StringUtils.equals(ServiceType.BINDCARDCONFIRM.name(), transRequest.getServiceType())) {
                //绑卡确认则解析返回值
                if (Integer.compare(1, transResult.getTransStatus()) == 0) {
                    //签约成功则记录入库
                    thirdProtocolBindCard = new ThirdProtocolBindCard();
                    thirdProtocolBindCard.setSubjectCode(transRequest.getSubjectCode());
                    thirdProtocolBindCard.setChannelCode(transRequest.getChannelCode().name());
                    thirdProtocolBindCard.setStatus(1);
                    thirdProtocolBindCard.setCardNo(AesUtils.encrypt(transRequest.getCardNo(), userInfoEncryptKey));
                    thirdProtocolBindCard.setName(AesUtils.encrypt(transRequest.getName(), userInfoEncryptKey));
                    thirdProtocolBindCard.setPhone(AesUtils.encrypt(transRequest.getPhone(), userInfoEncryptKey));
                    thirdProtocolBindCard.setIdCard(AesUtils.encrypt(transRequest.getIdCard(), userInfoEncryptKey));
                    thirdProtocolBindCardMapper.insert(thirdProtocolBindCard);
                }
            }
            return transResult;
        }
        return transResult;
    }

    @Override
    public TransResult wechatPayH5(PayRequest request) {
        TransRequest transRequest=new TransRequest();
        BeanUtils.copyProperties(request, transRequest);
        TransResult transResult = post(MethodConstants.WECHATPAYH5, transRequest);
        return transResult;
    }

    /**
     * 请求主体服务端
     * 对业务参数加密，请求加签名等
     *
     * @param method  请求的方法
     * @param request 交易参数
     * @return
     */
    private TransResult post(String method, TransRequest request) {
        String subjectCode = request.getSubjectCode();
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());
        transResult.setMsg("交易处理中");

        if (StringUtils.isBlank(subjectCode)) {
            log.error("subjectCode不能为空!");
            transResult.setMsg("subjectCode不能为空!");
            transResult.setTransStatus(2);
            return transResult;
        }
        if (null == request.getChannelCode()) {
            log.error("channelCode不能为空!");
            transResult.setMsg("channelCode不能为空!");
            transResult.setTransStatus(2);
            return transResult;
        }
        //接口安全处理，数据Aes加密、rsa加签名
        //获取本主体的私钥、主体服务端公钥（根据subjectCode获取）
        Subject subject = subjectService.getSubjectByCode(subjectCode);
        if (null == subject) {
            transResult.setMsg("subjectCode未定义，请联系管理员!");
            transResult.setTransStatus(2);
            return transResult;
        }

        String url = subject.getServiceUrl();
        if (StringUtils.isBlank(url)) {
            log.error("主体网关未配置，请联系管理员!");
            transResult.setMsg("主体网关未配置，请联系管理员!");
            transResult.setTransStatus(2);
            return transResult;
        }
        String subjectpayEndPublicKey = subject.getRsaPubKey();
        //获取中台私钥
        String privateKeyStr = systemCfgService.getConfigString(ConfigKeyEnums.PAY_PLATFORM_RSA_PRI_KEY.getCategory(), ConfigKeyEnums.PAY_PLATFORM_RSA_PRI_KEY.getName());
        if (StringUtils.isBlank(privateKeyStr)) {
            log.error("支付中台平台私钥未配置，请联系管理员!");
            transResult.setMsg("支付中台平台私钥未配置，请联系管理员!");
            transResult.setTransStatus(2);
            return transResult;
        }

        String aesKey = RandomStringUtils.randomAlphanumeric(16);
        String reqData = null;
        String oldAesKey = aesKey;
        //使用明文aesKey加密业务数据
        try {
            reqData = AesUtils.encrypt(JSONObject.toJSONString(request), aesKey);
        } catch (Exception e) {
            log.error("AES加密业务数据失败!", e);
            transResult.setMsg("AES加密业务数据失败!");
            transResult.setTransStatus(2);
            return transResult;
        }
        //使用主体服务端公钥加密aesKey
        try {
            aesKey = new String(Base64Utils.encode(RSAUtils.encryptByPublicKey(aesKey.getBytes("UTF-8"), subjectpayEndPublicKey)));
        } catch (Exception e) {
            log.error("RSA加密AES 密钥失败!", e);
            transResult.setMsg("RSA加密AES 密钥失败!");
            transResult.setTransStatus(2);
            return transResult;
        }
        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        postParameters.add("aesKey", aesKey);
        postParameters.add("subjectCode", subjectCode);
        postParameters.add("method", method);
        postParameters.add("reqData", reqData);

        Map<String, String> params = new TreeMap<String, String>();
        params.put("aesKey", aesKey);
        params.put("subjectCode", subjectCode);
        params.put("method", method);
        params.put("reqData", reqData);
        String jsoStr = JSONObject.toJSONString(params);

        PrivateKey privateKey = RSAUtils.readPrivateKey(privateKeyStr);
        String sign = null;
        try {
            sign = RSAUtils.sign("SHA1WithRSA", jsoStr.getBytes("UTF-8"), privateKey);
        } catch (Exception e) {
            log.error("rsa签名失败!", e);
            transResult.setMsg("rsa签名失败!");
            transResult.setTransStatus(2);
            return transResult;
        }
        postParameters.add("sign", sign);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity res = null;
        ThirdBills thirdBills = new ThirdBills();
        thirdBills.setBillNo(request.getBillNo());
        thirdBills.setMerchantBillNo(request.getMerchantBillNo());
        thirdBills.setStatus(1);
        thirdBills.setAmount(request.getAmount());
        thirdBills.setSubjectCode(request.getSubjectCode());
        thirdBills.setRequestUrl(url);
        thirdBills.setRequestText(reqData);
        thirdBills.setBeginTime(System.currentTimeMillis());
        thirdBills.setMethod(method);

        try {
            res = restTemplate.postForObject(url, postParameters, ResponseEntity.class);
            thirdBills.setStatus(1);
        } catch (Exception e) {
            log.error("调用主体服务端接口失败", e);
            thirdBills.setStatus(0);
        }
        thirdBills.setEndTime(System.currentTimeMillis());
        if (null == res) {
            //默认交易处理中
            thirdBills.setStatus(0);
            log.error("主体服务端接口返回空");
            transResult.setMsg("主体服务端接口返回空");
            transResult.setTransStatus(0);
            try {
                thirdBillsService.insert(thirdBills);
            } catch (Exception e) {
                log.error("插入第三方请求订单表失败:" + thirdBills.getBillNo(), e);
            }

            return transResult;
        }
        //TODO 此处后续可优化为异步处理
        try {
            thirdBills.setResponseText(JSONObject.toJSONString(res));
            thirdBillsService.insert(thirdBills);
        } catch (Exception e) {
            log.error("插入第三方请求订单表失败:" + thirdBills.getBillNo(), e);
        }
        if (StringUtils.equals(ResponseEntity.STATUS_FAIL, res.getStatus())) {
            //失败,中台服务一定要保证status=0一定是失败
            transResult.setTransStatus(2);
            transResult.setMsg("主体服务返回交易失败");
            return transResult;
        }
        if (StringUtils.equals(ResponseEntity.STATUS_OK, res.getStatus())) {
            //取data判断
            Object data = res.getData();
            if (null == data) {
                transResult.setTransStatus(0);
                transResult.setMsg("主体服务未返回业务结果");
                return transResult;
            }
            String dataEncrypt = (String) res.getData();
            String dataDecrypt = null;
            //解密
            try {
                dataDecrypt = AesUtils.decrypt(dataEncrypt, oldAesKey);
            } catch (Exception e) {
                log.error("主体返回业务数据Aes解密失败", e);
                transResult.setTransStatus(0);
                transResult.setMsg("中台返回业务数据Aes解密失败");
                return transResult;
            }
            if (StringUtils.isBlank(dataDecrypt)) {
                log.error("主体返回业务数据Aes解密失败");
                transResult.setTransStatus(0);
                transResult.setMsg("主体返回业务数据Aes解密失败");
                return transResult;
            }
            thirdBills.setResponseText(dataDecrypt);
            thirdBillsService.updateById(thirdBills);
            //解密成功转换成transResult
            TransResult resResult = null;
            try {
                resResult = JSONObject.parseObject(dataDecrypt, TransResult.class);
            } catch (Exception e) {
                log.error("主体返回业务数据转换失败", e);
                transResult.setTransStatus(0);
                transResult.setMsg("主体返回业务数据转换失败");
                return transResult;
            }
            if (null == resResult || null == resResult.getTransStatus()) {
                transResult.setTransStatus(0);
                transResult.setMsg("主体服务未返回业务结果");
                return transResult;
            }
            transResult.setTransStatus(resResult.getTransStatus());
            transResult.setTransTime(resResult.getTransTime());
            transResult.setMsg(resResult.getMsg());
            return transResult;
        }
        return transResult;
    }
}
